package com.xinyin.aiqinhaiback.service.impl;

import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.xinyin.aiqinhaiback.Utils.InformationTreeUtil;
import com.xinyin.aiqinhaiback.Utils.PortGroupingUtil;
import com.xinyin.aiqinhaiback.common.ConfigCache;
import com.xinyin.aiqinhaiback.common.Enum.ResultEnum;
import com.xinyin.aiqinhaiback.common.ResponseResult;
import com.xinyin.aiqinhaiback.exception.MyException;
import com.xinyin.aiqinhaiback.modbus.Modbus4jUtils;
import com.xinyin.aiqinhaiback.model.entity.*;
import com.xinyin.aiqinhaiback.service.InformationService;
import com.xinyin.aiqinhaiback.mapper.InformationMapper;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author zz0227
* @description 针对表【information】的数据库操作Service实现
* @createDate 2025-02-10 10:51:20
*/
@Service
public class InformationServiceImpl implements InformationService {
	@Resource
	private InformationMapper informationMapper;
	final String heatIp = ConfigCache.address.get("heatIp");
	final String coldIp = ConfigCache.address.get("coldIp");
	final String coolingTowerIp =  ConfigCache.address.get("coolingTowerIp");
	final String port =  ConfigCache.address.get("port");

	BatchResults<Integer> heatData = null;
	BatchResults<Integer> coldData = null;
	BatchResults<Integer> coolingTowerData = null;
	Modbus4jUtils heatModbus4jUtils = new Modbus4jUtils(heatIp,port);
	Modbus4jUtils coolingTowerModbus4jUtils = new Modbus4jUtils(coolingTowerIp,port);
	Modbus4jUtils coldModbus4jUtils = new Modbus4jUtils(coldIp,port);


	@Override
	public List<SensorInfo> getAllSensors() {
		return informationMapper.getAllSensors();
	}


	@Override
	public ResponseResult<List<InformationModel>> getThermalData() {
//		List<InformationModel> informationModelsCold = informationMapper.getColdThermal();
//		informationModelsCold.forEach(item -> {
//			List<Param> paramList = informationMapper.getInformationByDeviceId(item.getId());
//			paramList.forEach(paramListItem -> {
//				try {
//					paramListItem.setValue(modbus4jUtilsCold.getData(paramListItem.getModbus()).toString());
//				} catch (ModbusTransportException e) {
//					e.printStackTrace();
//				} catch (ErrorResponseException e) {
//					e.printStackTrace();
//				} catch (ModbusInitException e) {
//					e.printStackTrace();
//				}
//			});
//			item.setDataList(paramList);
//		});
//
//		List<InformationModel> informationModelsHeat = informationMapper.getHeatThermal();
//		informationModelsHeat.forEach(item -> {
//			List<Param> paramList = informationMapper.getInformationByDeviceId(item.getId());
//
//			paramList.forEach(paramListItem -> {
//				try {
//					paramListItem.setValue(modbus4jUtilsHeat.getData(paramListItem.getModbus()).toString());
//				} catch (ModbusTransportException e) {
//					e.printStackTrace();
//				} catch (ErrorResponseException e) {
//					e.printStackTrace();
//				} catch (ModbusInitException e) {
//					e.printStackTrace();
//				}
//			});
//
//
//			item.setDataList(paramList);
//		});
//
//		List<InformationModel> combinedList = Stream.concat(informationModelsCold.stream(), informationModelsHeat.stream())
//				.collect(Collectors.toList());
		return new ResponseResult<>(null);
	}

	@Override
	public List<Information> getAlldevices() {
		return informationMapper.getAllDevices();
	}

	// 更新 SensorInfo 的辅助方法
	private void updateSensorInfo(SensorInfo item, BatchResults<Integer> data, String targetIp) {
		if (data != null && item.getAddress().equals(targetIp)) {
			item.setValue(data.getValue(item.getModbus()));
		}
	}

	// 更新 Informations 的辅助方法
	private void updateInformations(Information item, BatchResults<Integer> data, String targetIp) {
		if (data != null && item.getAddress().equals(targetIp)) {
			item.setValue(data.getValue(item.getModbus()));
		}
	}

	@Override
	public ResponseResult<List<Map<String, Object>>> getDeviceInfo(DeviceReq req) {
		List<String> portList = new ArrayList<>(); //所有设备的 ip:端口号
		List<Information> informationList = informationMapper.getOneDeviceInfo(req);
		List<Map<String, Object>> res = null;
		try {

			informationList.forEach(item -> {
				portList.add(item.getAddress() + ":" + item.getModbus());
			});
			Map<String, Set<Integer>> map = PortGroupingUtil.groupPortsByIp(portList);//ip分组
			// 直接从 map 中获取寄存器地址
			Set<Integer> heatRegisters = map.get(heatIp);
			Set<Integer> coldRegisters = map.get(coldIp);
			Set<Integer> coolingTowerRegisters = map.get(coolingTowerIp);

			// 读取 Modbus 数据
			if (heatRegisters != null) {
				heatData = heatModbus4jUtils.batchRead(heatRegisters);
			}
			if (coldRegisters != null) {
				coldData = coldModbus4jUtils.batchRead(coldRegisters);
			}
			if (coolingTowerRegisters != null) {
				coolingTowerData = coolingTowerModbus4jUtils.batchRead(coolingTowerRegisters);
			}

			// 更新 sensorInfos
			BatchResults<Integer> finalHeatData = heatData;
			BatchResults<Integer> finalColdData = coldData;
			BatchResults<Integer> finalCoolingTowerData = coolingTowerData;

			synchronized (informationList) {
				informationList.forEach(item -> {
					updateInformations(item, finalHeatData, heatIp);
					updateInformations(item, finalColdData, coldIp);
					updateInformations(item, finalCoolingTowerData, coolingTowerIp);
				});
			}


			//处理数据为树形
			res= InformationTreeUtil.getData(informationList);


		} catch (ModbusInitException e) {
			e.printStackTrace();
		} catch (ModbusTransportException e) {
			e.printStackTrace();
		} catch (ErrorResponseException e) {
			e.printStackTrace();
		}
		return new ResponseResult<>(res);
	}

	@Override
	public void addAlarm(Alarm alarm) {
		informationMapper.addAlarm(alarm);
	}

	@Override
	public Alarm getAlarmInfo(Alarm alarm) {
		return informationMapper.getAlarmInfo(alarm);
	}

	@Override
	public void ensureAlarmStatus(Alarm alarm) {
		SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		alarm.setEnsureStatus(1);
		alarm.setEnsureTime(formatter.format(new Date().getTime()));
		informationMapper.ensureAlarmStatus(alarm);
	}

	@Override
	public Alarm getOldAlarmInfo(Alarm alarm) {

		return informationMapper.getOldAlarmInfo(alarm);
	}

	@Override
	public void updateRenewTime(Alarm oldAlarmInfo) {
		informationMapper.updateRenewTime(oldAlarmInfo);
	}

	@Override
	public  ResponseResult<AlarmViewData> getAlarmList() {
		AlarmViewData alarmViewData=new AlarmViewData();
		List<Alarm> alarms=informationMapper.getAlarmList();
		alarmViewData.setAlarmList(alarms);
		long isAlarmMount= alarms.stream().filter(alarm -> alarm.getIsAlarm()==1).count();
		alarmViewData.setIsAlarmMount(isAlarmMount);
		alarmViewData.setHistoryMount(alarms.size()-isAlarmMount);
		long unEnsureMount= alarms.stream().filter(alarm -> alarm.getRenewTime()!=null && alarm.getEnsureStatus()==0).count();
		alarmViewData.setUnEnSureMount(unEnsureMount);
		Alarm alarm = alarms.stream()
				.filter(d -> d.getIsAlarm() == 1)
				.limit(1).findFirst().orElse(new Alarm());
		alarmViewData.setCurrentAlarm(alarm);
		return new ResponseResult<>(alarmViewData);
	}

	@Override
	public void testadd() {

		for (int i = 0; i < 400; i++) {
			informationMapper.add();
		}
	}

	@Override
	@Transactional
	public void addDeviceHistoryDataList(List<DeviceHistoryData> deviceHistoryDatalist) {
		informationMapper.deviceHistoryDatalist(deviceHistoryDatalist);
	}

	@Override
	public void addSensorHistoryDataList(List<SensorHistoryData> sensorHistoryDataList) {
		informationMapper.addSensorHistoryDataList(sensorHistoryDataList);
	}

	@Override
	public ResponseResult getHistoryDevice() {
		List<DeviceHistoryItem> dataList=new ArrayList<>();
		List<SensorInfo> sensorInfoList= ConfigCache.data.get("sensors");
		List<Information> information = ConfigCache.data.get("devices");
		List<Information> informationList= information.stream().filter(item->item.getIsRecord()==1).collect(Collectors.toList());

		for (SensorInfo sensorInfo:sensorInfoList){
			DeviceHistoryItem deviceHistoryItem=new DeviceHistoryItem();
			deviceHistoryItem.setId(sensorInfo.getId());
			deviceHistoryItem.setName(sensorInfo.getSensorName()+"-"+sensorInfo.getSensorParamName());
			deviceHistoryItem.setType(1);
			dataList.add(deviceHistoryItem);
		}

		for (Information information1:informationList){
			DeviceHistoryItem deviceHistoryItem=new DeviceHistoryItem();
			deviceHistoryItem.setId(information1.getId());
			deviceHistoryItem.setName(information1.getDeviceName()+"-"+information1.getInformationName());
			deviceHistoryItem.setType(0);
			dataList.add(deviceHistoryItem);
		}
		return new ResponseResult(dataList);
	}

	@Override
	public ResponseResult getHistoryDeviceDetail(HistoryDataQuery historyDataQuery) {
		List<HistoryData> historyData=new ArrayList<>();
		if(historyDataQuery.getType()==0){
			historyData=informationMapper.getDeviceHistoryData(historyDataQuery);
		}
		if(historyDataQuery.getType()==1){
			historyData=informationMapper.getSensorHistoryData(historyDataQuery);
		}

		return new ResponseResult(historyData);
	}

	@Override
	public List<DeviceStatus> getDevicesName() {
		return informationMapper.getDevicesName();
	}

	@Override
	public List<HistoryResp> getDeviceHistoryDataByDate(LocalDate date,Integer deviceId,Integer deviceType) {
		List<DeviceHistoryResp> deviceHistoryData = new ArrayList<>();;
		List<DeviceHistoryResp> sensorHistoryData = new ArrayList<>();;
		if (deviceId == null && deviceType == null) {
			//获取设备表的历史数据
			deviceHistoryData = informationMapper.getDeviceHistoryDataByDate(date,deviceId);
			//获取传感器表的历史数据
			sensorHistoryData = informationMapper.getSensorHistoryDataByDate(date,deviceId);
		}else {
			if (deviceType == 0) {
				//获取设备表的历史数据
				deviceHistoryData = informationMapper.getDeviceHistoryDataByDate(date,deviceId);
			} else {
				//获取传感器表的历史数据
				sensorHistoryData = informationMapper.getSensorHistoryDataByDate(date,deviceId);
			}
		}
		//合并数据
		List<DeviceHistoryResp> allData = new ArrayList<>(deviceHistoryData);
		allData.addAll(sensorHistoryData);
		if (CollectionUtils.isEmpty(allData)) {
			return ListUtil.empty();
		}
		// 创建每十分钟的时间段列表
		List<String> allTimeSlots = createAllTimeSlots();
		// 按名称分组
		Map<String, List<DeviceHistoryResp>> groupedData = allData.stream()
				.collect(Collectors.groupingBy(DeviceHistoryResp::getName));

		// 构建结果列表
		List<HistoryResp> result = new ArrayList<>();

		for (Map.Entry<String, List<DeviceHistoryResp>> entry : groupedData.entrySet()) {
			String name = entry.getKey();
			Integer id = entry.getValue().get(0).getId();
			Integer type = entry.getValue().get(0).getType();
			Map<String, String> timeValueMap = entry.getValue().stream()
					.collect(Collectors.toMap(
							DeviceHistoryResp::getTime,
							DeviceHistoryResp::getValue,
							(v1, v2) -> v1));

			// 补全时间段
			List<DeviceHistoryResp> dataList = new ArrayList<>();
			for (String time : allTimeSlots) {
				String value = timeValueMap.getOrDefault(time, "0");
				dataList.add(new DeviceHistoryResp(time, name, value));
			}
			// 创建父对象
			HistoryResp historyResp = new HistoryResp();
			historyResp.setDeviceName(name);
			historyResp.setDeviceId(id);
			historyResp.setDate(date.toString());
			historyResp.setType(type);
			historyResp.setHistoryList(dataList);
			result.add(historyResp);
		}
		//将分组后的数据转换为返回数据类型
		return result;
	}

	@Override
	public void exportHistoryData(LocalDate startDate, LocalDate endDate, Integer deviceId, Integer deviceType, HttpServletResponse response) {
// 获取日期范围内的所有日期
		List<LocalDate> dateList = getDatesBetween(startDate, endDate);
		List<HistoryResp> historyExportList = new ArrayList<>();
		for (LocalDate date : dateList) {
			// 获取历史数据
			List<HistoryResp> historyRespList = getDeviceHistoryDataByDate(date, deviceId,deviceType);
			historyExportList.addAll(historyRespList);
		}

		Workbook workbook = new XSSFWorkbook();
		Sheet sheet = workbook.createSheet("历史数据");
//		// 创建表头样式
//		CellStyle headerStyle = workbook.createCellStyle();
//		Font headerFont = workbook.createFont();
//		headerFont.setBold(true); // 字体加粗
//		headerStyle.setFont(headerFont);
//		headerStyle.setBorderBottom(BorderStyle.THIN);
//		headerStyle.setBorderTop(BorderStyle.THIN);
//		headerStyle.setBorderLeft(BorderStyle.THIN);
//		headerStyle.setBorderRight(BorderStyle.THIN);
		// 创建表头
		Row headerRow = sheet.createRow(0);
//		List<String> allTimeSlots = createAllTimeSlots();
		Cell headerCell = headerRow.createCell(0);
		headerCell.setCellValue("日期");
		headerCell = headerRow.createCell(1);
		headerCell.setCellValue("设备名称"); // 修正：显示设备名称
//		for (int i = 0; i < allTimeSlots.size(); i++) {
			headerCell = headerRow.createCell(2);
			headerCell.setCellValue("值");
//		}

		// 创建日期时间格式化对象
		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

		// 填充数据
		int rowNum = 1;
		for (HistoryResp historyResp : historyExportList) {
			for (DeviceHistoryResp deviceHistoryResp : historyResp.getHistoryList()) {
				Row row = sheet.createRow(rowNum++);
				Cell cell = row.createCell(0);
				cell.setCellValue(LocalDateTime.of(LocalDate.parse(historyResp.getDate()), LocalTime.parse(deviceHistoryResp.getTime())).format(dateTimeFormatter));
				cell = row.createCell(1);
				cell.setCellValue(deviceHistoryResp.getName());
				cell = row.createCell(2);
				cell.setCellValue(deviceHistoryResp.getValue());
			}
		}
		String prefixName = "";
		if (deviceId == null && deviceType == null) {
			prefixName = "设备历史数据";
		}else {
			String name;
			if (deviceType == 0) {
				//查询设备名称
				name = informationMapper.getDeviceNameByInformationId(deviceId);
			}else {
				//查询传感器名称
				name = informationMapper.getSensorNameBySensorId(deviceId);
			}
			prefixName = name + "历史数据";
		}

		String suffixName = ".xlsx";
		String encodedName = null;
		try {
			encodedName = URLEncoder.encode(prefixName + suffixName, "UTF-8").replace("+", "%20");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("Unsupported encoding", e);
		}

		response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
		response.setCharacterEncoding("UTF-8");
		String header = String.format("attachment;filename=%s", encodedName);
		response.setHeader("Content-Disposition", header);
		response.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Type");

		// 写入响应流并确保流关闭
		try (OutputStream out = response.getOutputStream()) {
			workbook.write(out);
		} catch (Exception e) {
			throw new MyException(ResultEnum.EXPORT_ERROR);
		} finally {
			try {
				workbook.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 获取起始日期和结束日期之间的所有日期
	 *
	 * @param start 起始日期
	 * @param end   结束日期
	 * @return 日期列表
	 */
	public static List<LocalDate> getDatesBetween(LocalDate start, LocalDate end) {
		List<LocalDate> dates = new ArrayList<>();
		LocalDate currentDate = start;

		while (!currentDate.isAfter(end)) {
			dates.add(currentDate);
			currentDate = currentDate.plusDays(1);
		}

		return dates;
	}


	private List<String> createAllTimeSlots() {
		List<String> timeSlots = new ArrayList<>();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");

		for (int hour = 0; hour < 24; hour++) {
			for (int minute = 0; minute < 60; minute += 10) {
				LocalTime time = LocalTime.of(hour, minute);
				timeSlots.add(time.format(formatter));
			}
		}

		return timeSlots;
	}
}



